package com.packet.cheng.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.packet.cheng.annotation.RedisLock;
import com.packet.cheng.dto.RedPacketParamDTO;
import com.packet.cheng.dto.UserParamDTO;
import com.packet.cheng.entity.RedPacket;
import com.packet.cheng.entity.RedPacketRecord;
import com.packet.cheng.entity.User;
import com.packet.cheng.enumm.RedPacketTypeEnum;
import com.packet.cheng.enumm.RepacketStatusEnum;
import com.packet.cheng.mapper.RedPacketMapper;
import com.packet.cheng.mapper.RedPacketRecordMapper;
import com.packet.cheng.mapper.UserMapper;
import com.packet.cheng.service.RedPacketService;
import com.packet.cheng.service.UserService;
import com.packet.cheng.util.R;
import com.packet.cheng.vo.RedPacketReocrdVo;
import com.packet.cheng.vo.RedPacketVo;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author 张在成
 */
@Service
@Slf4j
public class RedPacketServiceImpl implements RedPacketService {

    @Resource
    private RedPacketMapper  redPacketMapper;

    @Resource
    private UserService userService;

    @Resource
    private RedPacketRecordMapper  redPacketRecordMapper;

    @Resource
    private Redisson redisson;



    private  static  ThreadLocal<DateFormat> tlFormat= ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));



//    @PostConstruct
//    public  void  init(){
//        System.out.println("获取缓存中的信息："+UserServiceImpl.get("user"));
//    }

    /**
     * Threadlocal保证线程是线程安全的
     * @param date
     * @return
     */
    public  static  String  parseDate(Date date){
        return tlFormat.get().format(date);
    }

    @RedisLock(key = "#orderId")
    @Override
    public  void  insertOrder(){
        System.out.println("远程调用-1：新增订单");  // 生成订单接口
        //---发送mq消息
        System.out.println("远程调用-2：减库存");
        System.out.println("远程调用-3：支付");
        System.out.println("远程调用-4：对接第三方物流");
        System.out.println("远程调用-5：修改订单状态");
    }

    /**
     * 发红包
     * @param redPacket
     * @param token
     * @return
     * @throws Exception
     */
    @Override
    public R<?> insertRedPacket(RedPacketParamDTO redPacket,String token) throws Exception {
        BigDecimal perMount = null;
        RedPacket redPacket1=new RedPacket();
        //认证用户是否登录
        R<User> user = userService.loginAuthticate(token);
        if (!StringUtils.isEmpty(user.getData().getId())){
            //拼手气红包
            if (redPacket.getType() == RedPacketTypeEnum.LUCKY.getType()){
                 if (StringUtils.isEmpty(redPacket.getTotalAmount())){
                     return R.data(406,"请设置拼手气红包总金额.....",0);
                }
                 // 传入红包总金额与红包总个数，计算单个红包金额的范围
                perMount = redPacket.getTotalAmount().divide(BigDecimal.valueOf(redPacket.getTotalPacket()), 2, BigDecimal.ROUND_HALF_UP);
                if (perMount.doubleValue() < 0.01){
                    return R.data(406,"单个金额不能小于0.01",0);
                }
                if (perMount.doubleValue() > 200){
                    return R.data(406,"单个金额不能大于200",0);
                }
                redPacket1.setTotalAmount(redPacket.getTotalAmount());
                redPacket1.setTotalPacket(redPacket.getTotalPacket());
                redPacket1.setLeftAmount(redPacket.getTotalAmount());
                redPacket1.setLeftPacket(redPacket.getTotalPacket());
            }

            //普通红包
            if (redPacket.getType()==RedPacketTypeEnum.ORDINARY.getType()){
                if (StringUtils.isEmpty(redPacket.getTotalAmount())){
                    return R.data(406,"请设置普通红包总金额",0);
                }
                // 传入单个金额和红包总个数，判断单个红包金额的范围
                perMount=redPacket.getAmountOne().multiply(BigDecimal.valueOf(redPacket.getTotalPacket()));
                if (redPacket.getAmountOne().doubleValue() < 0.01){
                    return  R.data(406,"单个金额不能小于0.01",0);
                }
                if (redPacket.getAmountOne().doubleValue() > 200) {
                    return  R.data(406,"单个金额不能超过200元",0);
                }
                redPacket1.setTotalAmount(perMount);
                redPacket1.setTotalPacket(redPacket.getTotalPacket());
                redPacket1.setAmountOne(redPacket.getAmountOne());
                redPacket1.setLeftAmount(perMount);
                redPacket1.setLeftPacket(redPacket.getTotalPacket());
            }

            //单个红包
            if (redPacket.getType()==RedPacketTypeEnum.ONE.getType()){
               if (StringUtils.isEmpty(redPacket.getAmountOne())){
                  return R.data(406,"请设置单个红包金额");
               }
               // 传入单个红包的金额，判断单个红包金额的范围
                //设置红包的范围
                if (redPacket.getAmountOne().doubleValue()<0.01){
                    return R.data(406,"单个金额不能小于0.01",0);
                }
                if (redPacket.getAmountOne().doubleValue()>200){
                    return R.data(406,"单个金额不能超过200元",0);
                }
                redPacket1.setTotalAmount(redPacket.getAmountOne());
                redPacket1.setTotalPacket(1);
                redPacket1.setAmountOne(redPacket.getAmountOne());
                redPacket1.setLeftAmount(redPacket.getAmountOne());
                redPacket1.setLeftPacket(1);
            }

            //红包信息入库
            redPacket1.setBlessing(redPacket.getBlessing());
            redPacket1.setCover(redPacket.getCover());
            redPacket1.setCreateDate(parseDate(new Date()));
            redPacket1.setUpdateDate(parseDate(new Date()));
            redPacket1.setExpireTime(parseDate(DateUtil.offsetDay(new Date(),1)));
            redPacket1.setIsValid(0);
            redPacket1.setStatus(RepacketStatusEnum.CREATE.getStatus());
            redPacket1.setUserId(user.getData().getId());
            redPacket1.setType(redPacket.getType());
            // 调用保存入库的数据
            boolean b = redPacketMapper.insertRedPacket(redPacket1);
            if (b) {
                return  R.data(200,"发红包成功",redPacket1.getId());
            }
        }
        return R.data(200,"");
    }

    /**
     * 抢红包
     * @param id
     * @param token
     * @return
     */
    //@Transactional(rollbackFor = Exception.class)
    @Override
    public R<RedPacketVo> grabRedPacket(String token, Integer id) throws Exception {
        if (StringUtils.isEmpty(id)||id<1){
            return  R.data(401,"请选择要抢的红包");
        }
        //获取登录用户
        R<User> user = userService.loginAuthticate(token);

        //通过红包id查询红包信息
        RedPacket redPacket = redPacketMapper.selectRedPacket(id);
        //判断红包信息是否存在
        if (Objects.isNull(redPacket)){
            return  R.data(406,"该红包不存在");
        }
        //通过红包id和用户id,判断用户是否领取过红包(不为空表示已领取，为空未领取)
        RedPacketRecord redPacketRecord = redPacketRecordMapper.getRedPacketRecordByUserId(id, user.getData().getId());

        RedPacketVo redPacketVo=null;

        //判断红包是否过期
        if (RepacketStatusEnum.EXPIRE.getStatus()==redPacket.getStatus()){

            if (Objects.isNull(redPacketRecord)){
                return R.data(400,"该红包已超过24小时,如已领取,请到红包记录中查看",redPacketRecord);
            }
            //设置红包状态为已过期
            redPacket.setStatus(RepacketStatusEnum.EXPIRE.getStatus());

            //封装返回的红包数据
            redPacketVo=buildRedPacketVo(redPacket,redPacketRecord);

            return  R.data(406,"已过期",redPacketVo);
        }
        //这个判断表示红包未过期，并且用户已领取
        if (!Objects.isNull(redPacketRecord)){

            redPacketVo=buildRedPacketVo(redPacket,redPacketRecord);

            return R.data(406,"用户已领取",redPacketVo);
        }
        //判断剩余红包个数
        if (redPacket.getLeftPacket()<1){
            return  R.data(406,"红包已抢完");
        }
        return R.data(200,"抢红包成功",null);
    }

    /**
     * 构建红包返回数据
     * @param redPacket
     * @param redPacketRecord
     * @return
     * @throws Exception
     */
    private RedPacketVo buildRedPacketVo(RedPacket redPacket, RedPacketRecord redPacketRecord) throws Exception {

        RedPacketVo redPacketVo=new RedPacketVo();
        BeanUtils.copyProperties(redPacket,redPacketVo);

        //设置红包id
        redPacketVo.setRedPacketId(redPacket.getId());
        UserParamDTO  userParamDTO=new UserParamDTO();
        userParamDTO.setId(redPacket.getUserId());
        //得到发红包用户
        User user = userService.selectUserById(userParamDTO);
        redPacketVo.setSendUserId(redPacket.getUserId());
        redPacketVo.setSendUserName(user.getNickName());
        if (!Objects.isNull(redPacketRecord)){
            //设置抢红包用户记录
            redPacketVo.setReceiveUserId(redPacketRecord.getUserId());
            redPacketVo.setReceiveAmount(redPacketRecord.getAmount());
        }
        //已领取红包个数=总红包数-剩余红包个数
        redPacketVo.setDrawRePacket(redPacket.getTotalPacket()-redPacket.getLeftPacket());
        //查询领过该红包的全部用户
        List<RedPacketRecord> redPacketRecords = redPacketRecordMapper.getRedPacketRecordById(redPacket.getId());
        redPacketVo.setRedPacketRecords(redPacketRecords);
        return  redPacketVo;
    }

    /**
     * 拆红包
     * @param id
     * @param token
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public R<RedPacketReocrdVo> apartRedPacket(String token,Integer id) throws Exception {

        if (StringUtils.isEmpty(id)||id<1){
            return  R.data(401,"请选择要抢的红包",id);
        }
        //获取登录用户
        R<User> user = userService.loginAuthticate(token);

        //通过红包id查询红包信息
        RedPacket redPacket = redPacketMapper.selectRedPacket(id);

        //判断红包信息是否存在
        if (Objects.isNull(redPacket)){
            return  R.data(406,"该红包不存在",0);
        }

        String  lockKey=redPacket.getId().toString() + "lockKey";

        // String threadId = String.valueOf(Thread.currentThread().getId());
        //获取锁，默认释放锁的时间是30s,并且还会重新启动一个线程进行锁续命
        RLock lock = redisson.getLock(lockKey);

        RedPacketReocrdVo  reocrdVo=null;

        try {
               lock.lock();

                //判断红包是否已过期
                if (RepacketStatusEnum.EXPIRE.getStatus() == redPacket.getStatus()){
                    return  R.data(406,"红包已过期","");
                }

                //判断红包个数是否为0
                if (redPacket.getLeftPacket()<1){
                    return  R.data(406,"红包已抢完",0);
                }
                //判断当前登录用户是否已经领取红包
                RedPacketRecord recordByUserId = redPacketRecordMapper.getRedPacketRecordByUserId(id, user.getData().getId());
                if (!Objects.isNull(recordByUserId)){
                    return  R.data(406,"已领取,可在“红包记录中”查看",recordByUserId);
                }
                //抢到的红包金额
                BigDecimal amount=BigDecimal.valueOf(0);

                // 拼手气红包
                if (redPacket.getType()==RedPacketTypeEnum.LUCKY.getType()){

                    if (redPacket.getLeftPacket()==1){
                        //剩余的金额就是最后一个红包
                        amount=redPacket.getLeftAmount();
                        Integer status = 2;
                        //更新红包状态
                        boolean b = redPacketMapper.updateRedPacketStatus(status,id);

                    }else{

                        // 二倍均值法计算每个人抢到的金额
                        BigDecimal result=redPacket.getLeftAmount().divide(BigDecimal.valueOf(redPacket.getLeftPacket()),2,BigDecimal.ROUND_HALF_UP);
                        result=result.multiply(BigDecimal.valueOf(2));

                        // 单位转换，元转为分
                        int limit= (int) (result.doubleValue()*100);

                        // 在指定范围获取随机数，将得到的值转换为元
                        amount=BigDecimal.valueOf(RandomUtil.randomInt(limit-1)+1).divide(BigDecimal.valueOf(100),2,BigDecimal.ROUND_HALF_UP);

                    }
                // 普通红包
                }else if (redPacket.getType()==RedPacketTypeEnum.ORDINARY.getType()){
                    // 如果是普通群红包，每个人抢到的就是固定的单个金额
                    if (redPacket.getLeftPacket() == 1){
                        Integer status = 2;
                        //更新红包状态
                        boolean b = redPacketMapper.updateRedPacketStatus(status,id);
                        if (b){
                            System.out.println("更新红包状态成功");
                        }
                    }
                    amount = redPacket.getAmountOne();
                // 单个红包
                } else if (redPacket.getType() == RedPacketTypeEnum.ONE.getType()) {
                    if (redPacket.getLeftPacket() == 1){
                        Integer status = 2;
                        //更新红包状态
                        boolean b = redPacketMapper.updateRedPacketStatus(status,id);
                        if (b){
                            System.out.println("更新红包状态成功");
                        }
                    }
                    amount = redPacket.getAmountOne();
                }

                //更新红包的剩余金额与数量
                int b = redPacketMapper.updateAmountAndNum(id,amount);
                if (b==0){
                    return  R.data(406,"红包已抢完");
                }
                //构建红包记录数据
                RedPacketRecord packetRecord = RedPacketRecord.builder()
                        .amount(amount)
                        .userId(user.getData().getId())
                        .redPacketId(id)
                        .createDate(parseDate(new Date()))
                        .updateDate(parseDate(new Date()))
                        .isValid(0)
                        .build();

                //保存红包记录
                int record = redPacketRecordMapper.insertRedPacketRecord(packetRecord);
                if (record==0){
                    return  R.data(406,"红包已抢完");
                }
                reocrdVo=new RedPacketReocrdVo();
                BeanUtils.copyProperties(redPacket,reocrdVo);
                UserParamDTO  userParamDTO=new UserParamDTO();
                userParamDTO.setId(redPacket.getUserId());
                User user1 = userService.selectUserById(userParamDTO);
                reocrdVo.setSendUserId(redPacket.getUserId());
                reocrdVo.setSendUserName(user1.getUsername());
                reocrdVo.setReceiveUserId(packetRecord.getUserId());
                reocrdVo.setReceiveAmount(amount);
                return R.data(200,"SUCCESS",reocrdVo);

        }finally {
             try {
                 //释放锁，判断当前用户是不是和抢红包的用户是同一个，同一个的话，释放锁
//                 if (user.getId().equals(reocrdVo.getReceiveUserId())){
//                 }
                    lock.unlock();
             }catch (Exception e){
                 e.printStackTrace();
                 log.error("释放锁失败{}",e.getMessage());
             }
        }
    }


    /**
     * 查看红包记录
     * @param redpacketId
     * @return
     */
    @Override
    public R<List<RedPacketRecord>> selectRedPacket(String token,Integer redpacketId) throws Exception {

        if (StringUtils.isEmpty(redpacketId)||redpacketId<1){
            return  R.data(401,"请选择查看的红包");
        }
        //获取登录用户
        R<User> user = userService.loginAuthticate(token);

        List<RedPacketRecord> record = redPacketRecordMapper.getRedPacketRecordById(redpacketId);

        if (Objects.isNull(record)){
            return  R.data(400,"该红包不存在");
        }

        return R.data(200,"SUCCESS",record);
    }
}
